package com.ryskoo.catering.productcate.repository;

import com.ryskoo.catering.productcate.domain.ProductCategoryPO;
import com.ryskoo.framework.core.bean.QueryConditionEnum;
import com.ryskoo.framework.core.bean.QueryMessageDTO;
import com.ryskoo.framework.core.repository.BasicJPAImpl;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.sort.SortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.hibernate.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Repository;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Repository
public class ProductCategoryJPAImpl extends BasicJPAImpl<ProductCategoryPO> implements IProductCategoryRepository {
    @Autowired
    ElasticsearchTemplate elasticsearchTemplate;

    @Override
    public List<ProductCategoryPO> getListByVendorId(String vendorId) {
        String hql = "from ProductCategoryPO o where o.vendorUuid = :vendorId and o.state = 1";
        Query query = getH4Session().createQuery(hql);
        query.setString("vendorId",vendorId);
        return query.list();
    }

    @Override
    public List<String> getUuidsByNameAndVendorId(String name, String vendorId) {
        String hql = "select o.uuid from ProductCategoryPO o where o.vendorUuid = :vendorId and o.name = :name";
        Query query = getH4Session().createQuery(hql);
        query.setString("vendorId",vendorId);
        query.setString("name",name);
        return query.list();
    }

    @Override
    public List<String> getUuidsByNameAndVendorIdForUpdate(String name, String vendorId, String uuid) {
        String hql = "select o.uuid from ProductCategoryPO o where o.vendorUuid = :vendorId and o.name = :name and uuid != :uuid";
        Query query = getH4Session().createQuery(hql);
        query.setString("vendorId",vendorId);
        query.setString("name",name);
        query.setString("uuid",uuid);
        return query.list();
    }

    @Override
    public void changeStatus(List<String> uuids, boolean status) {
        String hql = "update ProductCategoryPO o set o.state = :status where o.uuid in (:uuids)";
        Query query = getH4Session().createQuery(hql);
        query.setParameterList("uuids",uuids);
        query.setBoolean("status",status);
        query.executeUpdate();
    }

    @Override
    public int getMaxPosition(String vendorUuid) {
        String sql = "select max(o.position) from cater_product_category o where o.vendor_uuid = :vendorUuid";
        Query query = getH4Session().createSQLQuery(sql);
        query.setString("vendorUuid",vendorUuid);
        Object object = query.uniqueResult();
        if(null!=object){
            return (Integer)object;
        }else{
            return 0;
        }
    }

    @Override
    public List<ProductCategoryPO> queryFromES(QueryMessageDTO qm, boolean byPage) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        Map<String, Map<String, Object>> queryParams = qm.getQueryParams();
        for (Map.Entry<String, Map<String, Object>> entry : queryParams.entrySet()) {
            String field = entry.getKey();
            Map<String, Object> condition = entry.getValue();
            String operation = MapUtils.getString(condition, "operation");
            Object value = MapUtils.getObject(condition, "value");
            if (null != value && StringUtils.isNotBlank(value.toString())) {
                addOneCondition(boolQueryBuilder, field, value, operation);
            }
        }
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
        //分页查询
        if (byPage) {
            Pageable pageable = new PageRequest(qm.getQueryPage() - 1, qm.getPageShow());
            searchQueryBuilder.withPageable(pageable);
        }
        searchQueryBuilder.withQuery(boolQueryBuilder);

        SortBuilder sortBuilder = SortBuilders.fieldSort("position").order(SortOrder.ASC);
        searchQueryBuilder.withSort(sortBuilder);

        Page<ProductCategoryPO> searchResult = elasticsearchTemplate.queryForPage(searchQueryBuilder.build(), ProductCategoryPO.class);
        return searchResult.getContent();
    }

    @Override
    public int getCountFromES(QueryMessageDTO qm) {
        BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
        Map<String, Map<String, Object>> queryParams = qm.getQueryParams();
        for (Map.Entry<String, Map<String, Object>> entry : queryParams.entrySet()) {
            String field = entry.getKey();
            Map<String, Object> condition = entry.getValue();
            String operation = MapUtils.getString(condition, "operation");
            Object value = MapUtils.getObject(condition, "value");
            if (null != value && StringUtils.isNotBlank(value.toString())) {
                addOneCondition(boolQueryBuilder, field, value, operation);
            }
        }
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
        searchQueryBuilder.withQuery(boolQueryBuilder);
        return (int) elasticsearchTemplate.count(searchQueryBuilder.build(), ProductCategoryPO.class);
    }

    /**
     * 同步至ES
     *
     * @param list
     */
    @Override
    public void syncToElastic(List<ProductCategoryPO> list) {
        List<IndexQuery> indexQueryList = new ArrayList<>();
        for (ProductCategoryPO ProductCategory : list) {
            IndexQuery indexQuery = new IndexQueryBuilder().withObject(ProductCategory).build();
            indexQueryList.add(indexQuery);
        }
        elasticsearchTemplate.bulkIndex(indexQueryList);
        // 强制立即刷新
        elasticsearchTemplate.refresh(ProductCategoryPO.class);
    }

    /**
     * 删除ES里商品分类信息
     *
     * @param idList
     */
    @Override
    public void deleteProductFromES(List<String> idList) {
        for (String id : idList) {
            elasticsearchTemplate.delete(ProductCategoryPO.class, id);
        }
    }

    private void addOneCondition(BoolQueryBuilder queryBuilder, String name, Object value, String operation) {
        switch (QueryConditionEnum.valueOf(operation)) {
            case NE:
                queryBuilder.mustNot(QueryBuilders.termQuery(name, value));
                break;
            case EQ:
                queryBuilder.must(QueryBuilders.termQuery(name, value));
                break;
            case LIKE:
                queryBuilder.must(QueryBuilders.matchQuery(name, value));
                break;
            case LLIKE:
                queryBuilder.must(QueryBuilders.wildcardQuery(name, value + "*"));
                break;
            case RLIKE:
                queryBuilder.must(QueryBuilders.wildcardQuery(name, "*" + value));
                break;
            case GT:
                queryBuilder.must(QueryBuilders.rangeQuery(name).gt(value));
                break;
            case GE:
                queryBuilder.must(QueryBuilders.rangeQuery(name).gte(value));
                break;
            case LT:
                queryBuilder.must(QueryBuilders.rangeQuery(name).lt(value));
                break;
            case LE:
                queryBuilder.must(QueryBuilders.rangeQuery(name).lte(value));
                break;
            case IN:
                queryBuilder.must(QueryBuilders.termsQuery(name, value));
                break;
            case NOTIN:
                queryBuilder.mustNot(QueryBuilders.termsQuery(name, value));
                break;
            case BETWEEN:
                Object value1 = ((List) value).get(0);
                Object value2 = ((List) value).get(1);
                queryBuilder.must(QueryBuilders.rangeQuery(name).from(value1).to(value2));
                break;
            case OREQ:
                String[] eqArr = StringUtils.split(name, "#");
                BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
                for (String str : eqArr) {
                    boolQueryBuilder.should(QueryBuilders.termQuery(str, value));
                }
                queryBuilder.must(boolQueryBuilder);
                break;
            case ORLIKE:
                String[] liekArr = StringUtils.split(name, "#");
                BoolQueryBuilder likeBoolQueryBuilder = QueryBuilders.boolQuery();
                for (String str : liekArr) {
                    likeBoolQueryBuilder.should(QueryBuilders.matchQuery(str, value));
                }
                queryBuilder.must(likeBoolQueryBuilder);
                break;
            default:
        }
    }
}
